<?php

namespace App\Service\Cruise\Mission;

use App\Enums\BaseErrorCode;
use App\Enums\OpenShop\InvestmentPromotion\OrganizationManageEnum;
use App\Enums\OpenShop\InvestmentPromotion\SiteLocationEnum;
use App\Events\Cruise\CruiseOrder\CruiseOrderStatusChangeEvent;
use App\Exceptions\Custom\ResponseHttpException;
use App\Http\Middleware\OpenShop\UserPermissionAuth;
use App\Jobs\Cruise\CruiseCheckInputUploadTranscoding;
use App\Jobs\Cruise\RectifyExpire;
use App\Jobs\OpenShop\ChangeManagerJob;
use App\Library\Rms\RmsCurl;
use App\Library\Rms\RmsShopApi;
use App\Library\Rms\RmsUserApi;
use App\Models\Common\ConfigModel;
use App\Models\Common\FsCompanyRoleMappingModel;
use App\Models\Common\OperateLogModel;
use App\Models\Cruise\CruiseCheckAlbumModel;
use App\Models\Cruise\CruiseCheckCompanyModel;
use App\Models\Cruise\CruiseCheckDetailModel;
use App\Models\Cruise\CruiseCheckRectifyModel;
use App\Models\Cruise\CruiseCheckSelfDetailModel;
use App\Models\Cruise\CruiseCheckTaskGroupModel;
use App\Models\Cruise\CruiseOrderExamineLogModel;
use App\Models\Cruise\CruiseOrderInputModel;
use App\Models\Cruise\CruiseOrderModel;
use App\Models\Cruise\CruiseOrderProcessModel;
use App\Models\Cruise\CruiseTemplateModel;
use App\Models\Kms\Album\AlbumResourceModel;
use App\Models\OpenShop\Common\OpenShopOrderManagerModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopOrganizationManageModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopOrganizationManageUserModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopOrganizationRegionMappingModel;
use App\Models\OpenShop\Organization\OpenShopRegionManageMappingModel;
use App\Models\OpenShop\Organization\OpenShopRegionManageUserMappingModel;
use App\Models\OpenShop\SiteLocation\OpenShopSiteLocationModel;
use App\Models\Shop\ShopModel;
use App\Models\System\SystemNotifyCenterModel;
use App\Remote\Rms\RmsUserRemote;
use App\Service\BaseService;
use App\Service\Common\FsCardService;
use App\Service\Cruise\Check\CruiseCheckAgainstService;
use App\Service\Cruise\Check\CruiseCheckFsService;
use App\Service\Cruise\Check\CruiseCheckSpecialService;
use App\Service\Cruise\Disinfect\CruiseDisinfectService;
use App\Service\Cruise\Merchant\ShopSelfCheckNotifyConfigService;
use App\Service\OpenShop\Feishu\MessageSendService;
use App\Service\OpenShop\Feishu\OrganizationManageService;
use App\Service\OpenShop\User\RmsUserService;
use App\Service\System\SystemNotifyService;
use App\Support\CustomForm\AttributeCruiseSupport;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Kuafu\Nsq\NsqPublisher;

class CheckInputService extends CruiseOrderInputBaseService
{
    private ?CruiseOrderModel       $cruiseOrderModel;
    private ?CruiseCheckDetailModel $cruiseCheckDetailModel;
    private int                     $userId;

    public function __construct(int $cruiseOrderId, int $userId = 0)
    {
        $this->userId = $userId;

        $this->cruiseOrderModel = CruiseOrderModel::query()->where('id', $cruiseOrderId)->first();
        if (!$this->cruiseOrderModel) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "不存在的稽核任务ID:{$cruiseOrderId}");
        }

        $this->cruiseCheckDetailModel = CruiseCheckDetailModel::getDataByOrderId($this->cruiseOrderModel->id);
        if (!$this->cruiseCheckDetailModel) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, '未初始化cruiseCheckDetail信息');
        }

        parent::__construct($cruiseOrderId, $this->cruiseOrderModel->type, $this->cruiseCheckDetailModel->sysTemplate, $this->cruiseOrderModel);
    }

    /**
     * 获取享元
     * @return self
     */
    public static function getSingleton(int $cruiseOrderId, int $userId = 0): self
    {
        return Cache::store('array')->remember("CheckInputServiceSingleton:{$cruiseOrderId}:{$userId}", 120, function () use ($cruiseOrderId, $userId) {
            return new self($cruiseOrderId, $userId);
        });
    }

    /**
     * 初始化表单信息
     * @return void
     */
    public function initOrderInput(bool $forceUpdate = false, int $templateId = 0): void
    {
        if (!$templateId) {
            $templateId = CruiseTemplateModel::query()
                                             ->where('type', $this->templateType)
                                             ->where('sysTemplate', $this->sysTemplate)
                                             ->where('status', CruiseTemplateModel::STATUS_ON)
                                             ->value('id') ?? 0;
            if (!$templateId) {
                throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "获取模板类型对应模板失败:{$this->templateType}");
            }
        }

        // 幂等-不再创建
        if (!$forceUpdate && CruiseOrderInputModel::query()->where('orderId', $this->orderId)->where('templateType', $this->templateType)->count()) {
            return;
        }

        parent::baseInitOrderInput($templateId);
    }

    public function getInputObjectFill(): array
    {
        $submit = in_array($this->userId,
            $this->getCurrentHandlerInfo(CruiseOrderModel::STATUS_NOT_SUBMIT, false)['userIds'] ?? []); // 提交权限

        if ($submit && in_array($this->cruiseOrderModel->status,
                [CruiseOrderModel::STATUS_NOT_SUBMIT, CruiseOrderModel::STATUS_NOT_MODIFY])) {
            $disable = false;
        } else {
            $disable = true;
        }

        $data           = parent::baseGetInputObjectFill($disable);
        $data['submit'] = $submit; // 提交权限

        if ($this->cruiseOrderModel->status == CruiseOrderModel::STATUS_WAIT_MODIFY_EXT) {
            $status = CruiseOrderModel::STATUS_WAIT_MODIFY_EXT;
        } else {
            $status = CruiseOrderModel::STATUS_NOT_REVIEW;
        }

        $data['audit'] = in_array($this->userId, $this->getCurrentHandlerInfo($status, false)['userIds'] ?? []); // 审核权限

        $data['status']            = $this->cruiseOrderModel->status;
        $data['relationId']        = $this->cruiseOrderModel->type == CruiseOrderModel::TYPE_COMPANY_CHECK ? $this->cruiseOrderModel->cruiseCheckCompanyId : $this->cruiseOrderModel->shopId;  //稽核相册参数
        $data['module']            = $this->cruiseOrderModel->type;    //稽核相册参数
        $data['needAudit']         = true;
        $data['cruiseTemplateRel'] = null;
        if ($this->cruiseOrderModel->cruiseTemplateRel) {
            $data['cruiseTemplateRel'] = $this->cruiseOrderModel->cruiseTemplateRel->only([
                "id",
                "name",
                "desc",
                "type",
                "sysTemplate",
                "antiCheatingSwitch"
            ]);
        }

        return $data;
    }

    private array $inputObjects;

    /**
     * 获取所有巡检项
     * @return array
     */
    public function getCruiseItems(): array
    {
        if (!isset($this->inputObjects[$this->cruiseOrderModel->id])) {
            $this->inputObjects[$this->cruiseOrderModel->id] = parent::baseGetInputObjectFill(false)['lists'] ?? [];
        }

        $lists = $this->inputObjects[$this->cruiseOrderModel->id];

        foreach ($lists as &$projects) {
            foreach ($projects['projects'] as $k => &$project) {
                if (!in_array($project['inputType'], AttributeCruiseSupport::CRUISE_CHECK_MODULE)) {
                    unset($projects['projects'][$k]);
                }
            }

            $projects['projects'] = array_values($projects['projects']);
        }

        return $lists;
    }

    /**
     * 根据field获取project
     * @param string $field
     * @return array
     */
    public function getProject(string $field): array
    {
        if (!isset($this->inputObjects[$this->cruiseOrderModel->id])) {
            $this->inputObjects[$this->cruiseOrderModel->id] = parent::baseGetInputObjectFill(false)['lists'] ?? [];
        }

        foreach ($this->inputObjects[$this->cruiseOrderModel->id] as $projects) {
            foreach ($projects['projects'] as $project) {
                if ($project['field'] == $field) {
                    return $project;
                }
            }
        }

        return [];
    }

    public function saveUserContentJson(string $field, $value, array $auditValue = []): void
    {
        // 将数据添加到队列中去
        if (!empty($auditValue['files'])) {
            // 有文件才会验证
            dispatch(new CruiseCheckInputUploadTranscoding($this->cruiseOrderModel->id, $this->userId, $field, $value, $auditValue));
        }

        // 状态校验
        if (!in_array($this->cruiseOrderModel->status,
            [CruiseOrderModel::STATUS_NOT_SUBMIT, CruiseOrderModel::STATUS_NOT_MODIFY])) {
            $statusText = CruiseOrderModel::CRUISE_STATUS_MAPPING[$this->cruiseOrderModel->status] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "当前状态: {$statusText}，不允许修改");
        }

        // 角色校验
        $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);
        if (!in_array($this->userId, $handler['userIds'] ?? [])) {
            $userNames = $handler['userNames'] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null,
                "您无权操作，当前处理人：{$userNames}");
        }

        // 稽核相册使用
        $this->albumUsed($field, $auditValue, 'files');
        $this->albumUsed($field, $auditValue, 'rectifyFiles');

        parent::baseSaveUserContentJson($field, $value, $auditValue);

        if ($this->cruiseCheckDetailModel->firstSaveTime == 0) {
            $this->cruiseCheckDetailModel->firstSaveTime = time();
            $this->cruiseCheckDetailModel->save();
        }
    }

    public function submitOrder(): void
    {
        // 状态校验
        if (!in_array($this->cruiseOrderModel->status,
            [CruiseOrderModel::STATUS_NOT_SUBMIT, CruiseOrderModel::STATUS_NOT_MODIFY])) {
            $statusText = CruiseOrderModel::CRUISE_STATUS_MAPPING[$this->cruiseOrderModel->status] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "当前状态: {$statusText}，不允许提交");
        }

        // 提交时间校验
        $dealName = '';
        if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_8) {

            $cruiseCheckTask = $this->cruiseCheckDetailModel->cruiseTaskRel;
            if (!$cruiseCheckTask) {
                BaseService::throwErr("未找到任务详情cruise_check_tasks.id:{$this->cruiseCheckDetailModel->taskId}");
            }

            if (time() < $cruiseCheckTask->startTime) {
                BaseService::throwErr("任务未开始，开始时间：" . date('Y-m-d H:i:s', $cruiseCheckTask->startTime));
            }

            // 待提交才校验结束时间
            if ($this->cruiseOrderModel->status == CruiseOrderModel::STATUS_NOT_SUBMIT) {
                if (time() > $cruiseCheckTask->endTime) {
                    BaseService::throwErr("任务已结束，结束时间：" . date('Y-m-d H:i:s', $cruiseCheckTask->endTime));
                }
            }

            $dealName = (new RmsUserApi())->getUserInfoByIds([$this->userId], ['id', 'username'])['data'][0]['username'] ?? '';
        }

        // 角色校验
        $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);
        if (!in_array($this->userId, $handler['userIds'])) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null,
                "您无权操作，当前处理人：{$handler['userNames']}");
        }

        parent::baseSubmitOrder(true);

        // 提交后干的事
        $inputs        = (new CheckInputService($this->cruiseOrderModel->id, $this->userId))
            ->getInputObjectFill()['lists'];
        $signatureImgs = [];
        $totalNum      = $failNum = 0;
        $actualScore   = $totalScore = 0;

        foreach ($inputs as $input) {
            foreach ($input['projects'] as $i) {
                switch ($i['inputType']){
                    case AttributeCruiseSupport::INPUT_TYPE_SIGNATURE:
                    case AttributeCruiseSupport::INPUT_TYPE_PAYEE_INFO:
                        $signatureImgs = $i['value'] ?? [];
                        break;
                    case AttributeCruiseSupport::INPUT_TYPE_CRUISE_CHECK:
                        $totalNum++;
                        $options = collect($i['customAttributes']['options'])->sortByDesc('score')->keyBy('value');
                        // 不合格
                        if ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_FAIL) {
                            $failNum++;
                        } elseif ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_OK) {
                            $actualScore += ($options[$i['value']]['score'] ?? 0);
                        }

                        $totalScore += ($options->first()['score']);
                        break;
                    case AttributeCruiseSupport::INPUT_TYPE_CRUISE_CHECK_SKIP:
                    case AttributeCruiseSupport::INPUT_TYPE_CRUISE_CHECK_BIOLOGY:

                        $totalNum++;
                        $options = collect($i['customAttributes']['options'])->sortByDesc('score')->keyBy('value');
                        // 不合格
                        if ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_FAIL) {
                            $failNum++;
                        } elseif ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_OK) {
                            $actualScore += ($options[$i['value']]['score'] ?? 0);
                        } elseif ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_SKIP) {

                            // 不适用
                            break;
                        }

                        $totalScore += ($options->first()['score']);

                        break;
                }
            }
        }

        $successScore = floor($totalScore * 0.6);

        DB::beginTransaction();

        if ($this->cruiseCheckDetailModel->checkType == CruiseCheckDetailModel::CHECK_TYPE_THIRD_PARTY) {

            // 三方审核
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_WAIT_MODIFY_EXT;
        } else {

            // 总部审核
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_REVIEW;
        }
        $this->cruiseOrderModel->save();

        $this->cruiseCheckDetailModel->failNum      = $failNum;
        $this->cruiseCheckDetailModel->totalScore   = $totalScore;
        $this->cruiseCheckDetailModel->successScore = $successScore;
        $this->cruiseCheckDetailModel->actualScore  = $actualScore;
        $this->cruiseCheckDetailModel->submitTime   = time();
        $this->cruiseCheckDetailModel->isSignature  = $signatureImgs ? 1 : 0;
        $this->cruiseCheckDetailModel->totalNum     = $totalNum;
        $this->cruiseCheckDetailModel->createdByUid = $this->userId;

        if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_8) {
            $this->cruiseCheckDetailModel->dealUid = $this->userId;
            $this->cruiseCheckDetailModel->dealName = $dealName;
            $this->cruiseCheckDetailModel->reportResult = $this->cruiseCheckDetailModel->actualScore > $this->cruiseCheckDetailModel->successScore ? CruiseCheckDetailModel::REPORT_RESULT_QUALIFIED : CruiseCheckDetailModel::REPORT_RESULT_UNQUALIFIED;
        }

        $this->cruiseCheckDetailModel->save();

        // process
        CruiseOrderProcessModel::query()->create([
            'cruiseOrderId' => $this->cruiseOrderModel->id,
            'step'          => CruiseOrderProcessModel::PROCESS_SUBMITTED,
            'status'        => CruiseOrderProcessModel::STATUS_OK,
            'type'          => $this->cruiseOrderModel->type,
        ]);

        // 更新handlerId
        $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);

        DB::commit();

        // 任务表单状态变更事件
        event(new CruiseOrderStatusChangeEvent($this->cruiseOrderModel->id, CruiseOrderModel::STATUS_NOT_REVIEW));

        if (in_array($this->templateType, [CruiseTemplateModel::TYPE_3, CruiseTemplateModel::TYPE_5])) {

            // 通知对应审核人员
            (new CruiseCheckFsService($this->cruiseCheckDetailModel, $this->cruiseOrderModel))->audit();
        }

        // 发送NSQ
        CruiseDisinfectService::aboutCruiseOrderChangedPublishNsq('submitted', $this->cruiseOrderModel->toArray());
    }

    /**
     * @param array $data
     * @param int $isWebAudit 1-后台审核
     * @param int $whether 1-生成违约函
     * @throws GuzzleException
     * @throws \Exception
     */
    public function audit(array $data, $isWebAudit = 0, $whether = 0): void
    {
        // 状态校验
        if (!in_array($this->cruiseOrderModel->status,
            [CruiseOrderModel::STATUS_NOT_REVIEW, CruiseOrderModel::STATUS_NOT_MODIFY, CruiseOrderModel::STATUS_WAIT_MODIFY_EXT])) {
            $statusText = CruiseOrderModel::CRUISE_STATUS_MAPPING[$this->cruiseOrderModel->status] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "当前状态: {$statusText}，不允许提交");
        }

        // 角色校验
        $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);

        if (!in_array($this->userId, $handler['userIds'])) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null,
                "您无权操作，当前处理人：{$handler['userNames']}");
        }

        // 流程终结
        $finish = false;

        DB::beginTransaction();

        // 审核干的事
        if ($this->cruiseOrderModel->status == CruiseOrderModel::STATUS_NOT_REVIEW) {

            // 总部
            $this->cruiseCheckDetailModel->veto = CruiseCheckDetailModel::VETO_ON;
            if ($data['veto'] == CruiseCheckDetailModel::VETO_OFF) {
                $this->cruiseCheckDetailModel->actualScore = 0;
            }

//            $this->cruiseCheckDetailModel->qualityScore = $data['qualityScore'];
            $this->cruiseCheckDetailModel->reportResult = $this->cruiseCheckDetailModel->actualScore > $this->cruiseCheckDetailModel->successScore ? CruiseCheckDetailModel::REPORT_RESULT_QUALIFIED : CruiseCheckDetailModel::REPORT_RESULT_UNQUALIFIED;
            $this->cruiseCheckDetailModel->save();



            if($this->cruiseOrderModel->type != CruiseTemplateModel::TYPE_8){
                //工厂 - 任务变为已完成
                CruiseCheckSelfDetailModel::finish($this->cruiseOrderModel->id);

                CruiseCheckSpecialService::tryCompleteStatus($this->cruiseCheckDetailModel->taskId);

                $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_COMPLETE;
            }

            $this->cruiseOrderModel->save();


            // 插入process记录
            $processId = CruiseOrderProcessModel::query()->create([
                'cruiseOrderId' => $this->cruiseOrderModel->id,
                'step'          => CruiseOrderProcessModel::PROCESS_REVIEWED,
                'status'        => $data['auditStatus'],
                'type'          => $this->cruiseOrderModel->type,
            ])->id;

            // 插入examine记录
            CruiseOrderExamineLogModel::query()->create([
                'processId' => $processId,
                'content'   => $data['auditContent'],
                'status'    => $data['auditStatus'],
            ]);

            if ($this->cruiseOrderModel->type != CruiseTemplateModel::TYPE_8) {

                // 插入process记录
                CruiseOrderProcessModel::query()->create([
                    'cruiseOrderId' => $this->cruiseOrderModel->id,
                    'step'          => CruiseOrderProcessModel::PROCESS_COMPLETED,
                    'status'        => $data['auditStatus'],
                    'type'          => $this->cruiseOrderModel->type,
                ])->id;
            }

            $finish = true;

        } elseif ($this->cruiseOrderModel->status == CruiseOrderModel::STATUS_WAIT_MODIFY_EXT) {

            // 插入process记录
            $processId = CruiseOrderProcessModel::query()->create([
                'cruiseOrderId' => $this->cruiseOrderModel->id,
                'step'          => CruiseOrderProcessModel::PROCESS_EXT_REVIEWED,
                'status'        => $data['auditStatus'],
                'type'          => $this->cruiseOrderModel->type,
            ])->id;

            // 插入examine记录
            CruiseOrderExamineLogModel::query()->create([
                'processId' => $processId,
                'content'   => $data['auditContent'],
                'status'    => $data['auditStatus'],
            ]);


            // 三方
            // 同意、不同意、
            if ($data['auditStatus'] == CruiseOrderProcessModel::STATUS_OFF) {

                // 驳回
                $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_MODIFY;
                $this->cruiseOrderModel->save();

                // 通知提交人驳回信息
                (new CruiseCheckFsService($this->cruiseCheckDetailModel, $this->cruiseOrderModel))->reject($this->userId, $data['auditContent']);

                // 发送NSQ
                CruiseDisinfectService::aboutCruiseOrderChangedPublishNsq('rejected', $this->cruiseOrderModel->toArray());
            } else {

                $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_REVIEW;
                $this->cruiseOrderModel->save();
            }
        }

        DB::commit();

        if ($finish) {

            // 生成整改单
            $composeRectifyRes = $this->composeRectify();

            // 完成通知相关人员
            (new CruiseCheckFsService($this->cruiseCheckDetailModel, $this->cruiseOrderModel))->finish($this->userId);

            if (in_array($this->cruiseOrderModel->type, [CruiseTemplateModel::TYPE_3, CruiseTemplateModel::TYPE_8])) {
                // 向商家发送巡检报告生成提醒
                $userIds = array_column(RmsUserRemote::getShopManagerUserByShopId([$this->cruiseOrderModel->shopId], [], true)['lists'] ?? [], 'userId');//通过shopId 获得对应店长的 userId;
                $notify = SystemNotifyService::save(
                    false,
                    $title = "您有1条巡检报告已生成，请查收！",
                    SystemNotifyCenterModel::NOTIFY_TYPE_3,
                    SystemNotifyCenterModel::NOTIFY_TARGET_1,
                    '',
                    $title,
                    config('webUrl.notify_web_cdn_url') . "#/pages/audit/report/detail/detail?id={$this->cruiseCheckDetailModel->id}",
                    SystemNotifyCenterModel::METHOD_TYPE_AUTOMATIC,
                    $title,
                    '',
                    SystemNotifyCenterModel::IS_POPUP_OFF,
                    1,
                    $this->cruiseOrderModel->shopId
                );
                SystemNotifyService::recordLog($notify, '创建消息');
                SystemNotifyService::preSend($notify->id, $userIds);

                //后台审核-稽核报告审核完应该自动抄送省区和对应的督导
                if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_3 && $isWebAudit == 1) {
                    self::sendFsNotice($this->cruiseCheckDetailModel, $this->cruiseOrderModel->shopId, $whether, $composeRectifyRes);
                }
            }

            // 发送NSQ
            CruiseDisinfectService::aboutCruiseOrderChangedPublishNsq('finished', $this->cruiseOrderModel->toArray());

        } else {

            // 更新handlerId
            $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);

            if ($data['auditStatus'] == CruiseOrderProcessModel::STATUS_OK) {

                // 通知对应审核人员
                (new CruiseCheckFsService($this->cruiseCheckDetailModel, $this->cruiseOrderModel))->audit();
            }
        }
    }


    /**
     * 生成整改单
     * @return array
     * @throws GuzzleException
     */
    private function composeRectify(): array
    {
        $failFields = [];         // 不合格的巡检项
        $total      = 0;          //总巡检项
        $inputs        = $this->getInputObjectFill()['lists'];
        foreach ($inputs as $input) {
            foreach ($input['projects'] as $i) {
                if (in_array($i['inputType'], AttributeCruiseSupport::CRUISE_CHECK_MODULE)) {
                    $total++;
                    // 不合格
                    if ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_FAIL) {

                        // 现场未整改
                        $rectifyStatus = $i['customAttributes']['auditValue']['rectifyStatus'] ?? AttributeCruiseSupport::RECTIFY_STATUS_UNDONE;
                        if ($rectifyStatus == AttributeCruiseSupport::RECTIFY_STATUS_UNDONE) {
                            $failFields[] = $i['field'];
                        }
                    }
                }
            }
        }

        // 没有异常
        if (!$failFields) {
            return ['total' => $total, 'failTotal' => 0, 'auditEndTime' => 0, 'submitEndTime' => 0];
        }

        DB::beginTransaction();

        // insert
        [$submitEndTime, $auditEndTime] = CruiseCheckRectifyModel::batchAdd($this->cruiseOrderModel->shopId,
            $this->cruiseCheckDetailModel->id, $this->cruiseOrderModel->id, $failFields, $this->cruiseOrderModel->cruiseCheckCompanyId);

        // 初始化整改单流程进度
        $operateLogModel = (new OperateLogModel());
        CruiseCheckRectifyModel::query()
                               ->where('cruiseCheckDetailId', $this->cruiseCheckDetailModel->id)
                               ->pluck('id')
                               ->each(function ($rectifyId) use (&$operateLogModel) {
                                   $operateLogModel->setParam(OperateLogModel::BUSINESS_RECTIFY_DETAIL, $rectifyId, 0,
                                       '生成整改单', '', OperateLogModel::STATUS_OK, $this->userId, '', $this->userId);
                               });
        $operateLogModel->addBatch();

        DB::commit();

        // 门店稽核才考虑违约函
        if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_3) {

            // 过期job
            if ($auditEndTime && $auditEndTime > time()) {
                dispatch((new RectifyExpire($this->cruiseCheckDetailModel->id))->onQueue('{check-expire}'))->delay($auditEndTime - time());
                //商家消息及阿里云语音通知
                CruiseCheckAgainstService::sendSystemNotify($this->cruiseOrderModel->shopId, $auditEndTime, CruiseCheckAgainstService::PUNISH_CRUISE_CHECK_RECTIFY, 0, 0, count($failFields));
            }
        }

        return ['total' => $total, 'failTotal' => count($failFields), 'auditEndTime' => $auditEndTime, 'submitEndTime' => $submitEndTime];
    }

    /**
     * 获取阶段对应处理人
     * @return array
     */
    public function getCurrentHandlerInfo(int $status, bool $adjust = true): array
    {
        $arr = [];

        // 门店稽核
        if (in_array($this->cruiseOrderModel->type, [CruiseTemplateModel::TYPE_3, CruiseTemplateModel::TYPE_8])) {
            switch ($status) {
                case CruiseOrderModel::STATUS_NOT_SUBMIT:
                case CruiseOrderModel::STATUS_NOT_MODIFY:
                case CruiseOrderModel::STATUS_CLOSED:

                    if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_3) {

                        // 稽核顾问
                        $arr = [
                            'userIds'   => [(int)$this->cruiseCheckDetailModel->dealUid],
                            'userNames' => (string)$this->cruiseCheckDetailModel->dealName,
                        ];
                    } elseif ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_8) {

                        $users = RmsCurl::getIns()->do('api/internal/user/usersInShop', ['shopId' => $this->cruiseOrderModel->shopId], 'GET')['data'] ?? [];

                        // 门店权限人员
                        $arr = [
                            'userIds'   => array_column($users, 'id'),
                            'userNames' => implode(',', array_column($users, 'username')),
                        ];
                    }

                    break;
                case CruiseOrderModel::STATUS_NOT_REVIEW:
                case CruiseOrderModel::STATUS_COMPLETE:

                    if ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_3) {

                        // 总部负责人
                        $arr = [
                            'userIds'   => $userIds = ConfigModel::getCruiseCheckAudit($this->cruiseCheckDetailModel->companyId, $this->cruiseOrderModel->type ?? 0, FsCompanyRoleMappingModel::ROLE_ID_KF_REVIEWER),
                            'userNames' => collect(RmsUserRemote::getRmsUserByIds($userIds))->implode('username', ','),
                        ];
                    } elseif ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_8) {

                        // 自检审核人
                        // 督导、城市经理、省总、战区总
                        list($userIds, $userNames) = $this->getManagers();

                        $arr = [
                            'userIds'   => $userIds,
                            'userNames' => $userNames,
                        ];
                    }

                    break;
                case CruiseOrderModel::STATUS_WAIT_MODIFY_EXT:

                    // 三方负责人
                    $arr = [
                        'userIds'   => $userIds = ConfigModel::getCruiseCheckAudit($this->cruiseCheckDetailModel->companyId, $this->cruiseOrderModel->type),
                        'userNames' => collect(RmsUserRemote::getRmsUserByIds($userIds))->implode('username', ','),
                    ];

                    break;
                default:
                    return [
                        'userIds'   => [],
                        'userNames' => '',
                    ];
            }
        } elseif ($this->cruiseOrderModel->type == CruiseTemplateModel::TYPE_5) {

            switch ($status) {
                case CruiseOrderModel::STATUS_NOT_SUBMIT:
                case CruiseOrderModel::STATUS_NOT_MODIFY:
                case CruiseOrderModel::STATUS_CLOSED:

                    // 巡检人
                    $arr = [
                        'userIds'   => [(int)$this->cruiseCheckDetailModel->dealUid],
                        'userNames' => (string)$this->cruiseCheckDetailModel->dealName,
                    ];

                    break;
                case CruiseOrderModel::STATUS_NOT_REVIEW:
                case CruiseOrderModel::STATUS_COMPLETE:

                    $company = CruiseCheckCompanyModel::getDataById($this->cruiseOrderModel->cruiseCheckCompanyId);

                    // 总部负责人
                    $arr = [
                        'userIds'   => [$company['kfManager']['rmsUserId']],
                        'userNames' => $company['kfManager']['name'],
                    ];

                    break;
                case CruiseOrderModel::STATUS_WAIT_MODIFY_EXT:

                    // 三方负责人
                    $arr = [
                        'userIds'   => $userIds = ConfigModel::getCruiseCheckAudit($this->cruiseCheckDetailModel->companyId, $this->cruiseOrderModel->type),
                        'userNames' => collect(RmsUserRemote::getRmsUserByIds($userIds))->implode('username', ','),
                    ];

                    break;
                default:
                    return [
                        'userIds'   => [],
                        'userNames' => '',
                    ];
            }
        }

        $userIds = $arr['userIds'] ?? [];
        if ($adjust && $this->cruiseOrderModel && $userIds && !in_array($this->cruiseOrderModel->handlerId, $userIds)) {
            $this->cruiseOrderModel->handlerId = $userIds[0] ?? 0;
            $this->cruiseOrderModel->save();
        }

        return $arr;
    }

    /**
     * 督导评价扣分
     * @return void
     */
    public function auditDeductScores(array $fieldsScore): void
    {
        /**
         * $fieldsScore = ["dian_nei_hua_xue_pin_dan_5WRo3i" => 5, "dian_nei_shi_cai_bao_3E52s1" => 0];
         */

        // 状态校验
        if (!in_array($this->cruiseOrderModel->status, [CruiseOrderModel::STATUS_NOT_REVIEW])) {
            self::throwErr("当前状态不允许修改");
        }

        // 角色校验
        switch ($this->cruiseOrderModel->type) {
            case CruiseOrderModel::TYPE_COMPANY_CHECK:
                $handler['userIds'] = [object_get($this->cruiseOrderModel, 'cruiseCheckCompanyRel.kfManagerId', 0)];
                $handler['userNames'] = (new RmsUserApi())->getUserInfoByIds($handler['userIds'], ['username'])['data'][0]['username'];
                break;
            default:
                $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);
        }
        if (!in_array($this->userId, $handler['userIds'])) {
            self::throwErr("您无权操作，当前处理人：{$handler['userNames']}");
        }

        $batchFieldsKeyValue = [];
        $totalDeductScore = 0;
        foreach ($fieldsScore as $field => $deductScore) {
            $batchFieldsKeyValue[$field] = ['deductScore' => $deductScore];
            $totalDeductScore += $deductScore;
        }

        if ($totalDeductScore > 100) {
            self::throwErr("扣分不能超过100");
        }

        parent::baseSaveUserContentJson($field, self::IGNORE_SAVE_VALUE, self::IGNORE_SAVE_AUDIT_VALUE, function ($arr) use ($fieldsScore) {

            foreach ($fieldsScore as $field => $deductScore) {
                $arr[$field.'_deductScore'] = $deductScore;
            }

            return $arr;
        });

        $this->cruiseCheckDetailModel->qualityScore = 100 - $totalDeductScore;
        $this->cruiseCheckDetailModel->save();
    }

    /**
     * 夸父总部稽核管理员 - 对整改单的驳回
     * @param string $content 驳回意见
     * @return void
     */
    public function kfReject(string $content = '')
    {
        if (null == $this->cruiseOrderModel || $this->cruiseOrderModel->status != CruiseOrderModel::STATUS_NOT_REVIEW) {
            self::throwErr('任务已作废或者任务状态不正确');
        }

        DB::beginTransaction();

        // 驳回
        $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_MODIFY;
        $this->cruiseOrderModel->save();

        $this->cruiseCheckDetailModel->failNum      = 0;
        $this->cruiseCheckDetailModel->totalScore   = 0;
        $this->cruiseCheckDetailModel->successScore = 0;
        $this->cruiseCheckDetailModel->actualScore  = 0;
        $this->cruiseCheckDetailModel->submitTime   = 0;
        $this->cruiseCheckDetailModel->isSignature  = 0;
        $this->cruiseCheckDetailModel->totalNum     = 0;
        $this->cruiseCheckDetailModel->save();


        //添加日志
        // 插入process记录
        $processId = CruiseOrderProcessModel::query()->create([
            'cruiseOrderId' => $this->cruiseOrderModel->id,
            'step'          => CruiseOrderProcessModel::PROCESS_REVIEWED,
            'status'        => CruiseOrderProcessModel::STATUS_OFF,
            'type'          => CruiseOrderModel::TYPE_CHECK,
        ])->id;

        // 插入examine记录
        CruiseOrderExamineLogModel::query()->create([
            'processId' => $processId,
            'content'   => $content,
            'status'    => CruiseOrderModel::TYPE_CHECK,
        ]);

        DB::commit();

        // 驳回推送
        (new CruiseCheckFsService($this->cruiseCheckDetailModel, $this->cruiseOrderModel))->reject($this->userId, $content);

        // 发送NSQ
        CruiseDisinfectService::aboutCruiseOrderChangedPublishNsq('rejected', $this->cruiseOrderModel->toArray());
    }


    /**
     * 稽核报告审核完应该自动抄送省区和对应的督导
     * @param $cruiseCheckDetailModel //巡检报告信息
     * @param $shopId //店铺ID
     * @param $whether //1-已生成违约函
     * @param $composeRectifyRes //生成整改单的返回
     * @throws GuzzleException
     */
    public static function sendFsNotice($cruiseCheckDetailModel, $shopId, $whether, $composeRectifyRes)
    {
        $shop     = (new RmsShopApi())->getShopByIds([$shopId])['data']['shopList'][0] ?? [];
        $shopCode = $shop['shopCode'] ?? '';
        $url      = \App\Service\OpenShop\Feishu\BaseService::getCruiseCheckDetailUrl($cruiseCheckDetailModel->id);

        try {
            $manager = OrganizationManageService::getOrganizationInfoByType(
                OrganizationManageEnum::TYPE_BRANCH_OFFICE, $shop['province']
            );
        } catch (\Exception $exception) {//处理 该省区没有绑定开店组织 不显示
            $manager = [];
        }
        $setKfUserIds = [];
        if (isset($shop['councilorId']) && $shop['councilorId']) {
            $setKfUserIds[] = $shop['councilorId'];
        }
        if (isset($manager["operationUid"]) && $manager["operationUid"]) {//督导+省总
            $setKfUserIds[] = $manager["operationUid"];
        }

        // 城市经理
        if (isset($manager["id"]) && $manager["id"]) {
            $managers = OpenShopOrganizationManageUserModel::getData($manager["id"], OpenShopOrganizationManageUserModel::TYPE_CITY_MANAGER);
            if ($managers) {
                $setKfUserIds = array_merge($setKfUserIds, array_column($managers, 'userId'));
            }
        }
        $setKfUserIds = array_unique($setKfUserIds);
        if (!$setKfUserIds) {//没有要发送的人，直接返回
            return;
        }

        $title = $shopCode . '巡检报告已生成';
        $score = $auditEndTime = $lastEmpty = 'notShow';
        $auditEndDate = $composeRectifyRes['submitEndTime'] ? date('Y-m-d', $composeRectifyRes['submitEndTime']) : date('Y-m-d');//整改截止日期
        $actualScore  = $cruiseCheckDetailModel->totalScore != 0 ? (int)($cruiseCheckDetailModel->actualScore / $cruiseCheckDetailModel->totalScore * 100) : 0;
        if ($whether == 1) {//已生成违约函
            $color               = 'red';
            $title               = '【违约】' . $title;
            $businessCooperation = "**商家配合：**\n<font color='red'>整改、违约</font>";
            $score               = "**稽核得分：**\n" . $actualScore;
            $auditEndTime        = "**整改截止日期：**\n" . $auditEndDate;
            $lastEmpty           = '';
        } else {
            if ($composeRectifyRes['failTotal'] == 0) {//无不合格的巡检项，不生成整改单
                $color               = 'green';
                $businessCooperation = "**稽核得分：**\n" . $actualScore;
            } else {//只生成整改单
                $color               = 'yellow';
                $title               = '【整改】' . $title;
                $businessCooperation = "**商家配合：**\n<font color='red'>整改</font>";
                $score               = "**稽核得分：**\n" . $actualScore;
                $auditEndTime        = "**整改截止日期：**\n" . $auditEndDate;
                $lastEmpty           = '';
            }
        }

        (new FsCardService())
            // 设置文件path， 如果不设置，取默认通用卡片：CruiseCheck/feishu/notifyTemplate/generalV2.json
            ->setPath("CruiseCheck/feishu/notifyTemplate/cruise_report.json")
            // 设置elementFields
            ->buildElementField($businessCooperation)
            ->buildElementField("**门店信息：**\n" . $shopCode . ($shop['name'] ?? ''))
            ->buildElementField("")
            ->buildElementField("")
            ->buildElementField("**巡检人：**\n" . $cruiseCheckDetailModel->dealName)
            ->buildElementField("**巡检日期：**\n" . date('Y-m-d', $cruiseCheckDetailModel->submitTime))
            ->buildElementField($lastEmpty)
            ->buildElementField($lastEmpty)
            ->buildElementField($score)
            ->buildElementField($auditEndTime)
            // 使用通配符，替换json中固定的变量
            ->setWildCardData(
                [
                    'num1'  => $composeRectifyRes['total'],
                    'num2'  => $composeRectifyRes['failTotal'],
                    'num3'  => $composeRectifyRes['failTotal'],
                    'url'   => $url,
                    'color' => $color,
                    'title' => $title,
                ]
            )
            ->replace(true)
            // 设置推送的userId
            ->setKfUserIds($setKfUserIds)
            // 设置推送的机器人
            ->setModule(UserPermissionAuth::MODULE_CRUISE_CHECK)
            // send
            ->baseSend();
    }

    /**
     * 自检督导审核,每步保存
     * @return void
     */
    public function selfCheckAuditSave(string $field, int $value, string $instructions)
    {
        // 状态校验
        if (!in_array($this->cruiseOrderModel->status, [CruiseOrderModel::STATUS_NOT_REVIEW])) {
            $statusText = CruiseOrderModel::CRUISE_STATUS_MAPPING[$this->cruiseOrderModel->status] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "当前状态: {$statusText}，不允许督导审核");
        }

        // 角色校验
        $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);
        if (!in_array($this->userId, $handler['userIds'] ?? [])) {
            $userNames = $handler['userNames'] ?? '';
            BaseService::throwErr("您无权操作，当前处理人：{$userNames}");
        }

        // 更新字段
        $this->saveAuditSecond($field, $value, $instructions);
    }

    /**
     * 自检督导审核，最终提交
     * @return void
     */
    public function selfCheckAuditSubmit()
    {
        // 状态校验
        if (!in_array($this->cruiseOrderModel->status, [CruiseOrderModel::STATUS_NOT_REVIEW])) {
            $statusText = CruiseOrderModel::CRUISE_STATUS_MAPPING[$this->cruiseOrderModel->status] ?? '';
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "当前状态: {$statusText}，不允许督导审核");
        }

        // 角色校验
        $handler = $this->getCurrentHandlerInfo($this->cruiseOrderModel->status);
        if (!in_array($this->userId, $handler['userIds'] ?? [])) {
            $userNames = $handler['userNames'] ?? '';
            BaseService::throwErr("您无权操作，当前处理人：{$userNames}");
        }

        // 检查所有字段都审核了
        $errorAuditNum = 0;

        $inputs        = $this->getInputObjectFill()['lists'];
        foreach ($inputs as $input) {
            foreach ($input['projects'] as $i) {
                if (in_array($i['inputType'], AttributeCruiseSupport::CRUISE_CHECK_MODULE)) {


                    // 不合格
                    if ($i['value'] == AttributeCruiseSupport::CRUISE_CHECK_FAIL) {
                        $errorAuditNum++;

                        if (!isset($i['customAttributes']['auditValue']['instructions']) || !$i['customAttributes']['auditValue']['instructions']) {
                            BaseService::throwErr("请先审核完所有巡检项");
                        }
                    }
                }
            }
        }

        DB::beginTransaction();

        // 有异常
        if ($errorAuditNum > 0) {
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_AUDIT_ERROR;
        } else {

            // 无异常
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_AUDIT_OK;
        }

        $this->cruiseOrderModel->save();

        // 不合格数量
        $this->cruiseCheckDetailModel->selfAuditErrorNum = $errorAuditNum;
        $this->cruiseCheckDetailModel->save();

        // 审核日志
        // 插入process记录
        CruiseOrderProcessModel::query()->create([
            'cruiseOrderId' => $this->cruiseOrderModel->id,
            'step'          => CruiseOrderProcessModel::PROCESS_SELF_REVIEWED,
            'status'        => CruiseOrderProcessModel::STATUS_OK,
            'type'          => $this->cruiseOrderModel->type,
            'createdByUid'  => $this->userId,
            'updatedByUid'  => $this->userId,
        ])->id;

        DB::commit();

        // 门店自检任务表单状态发生变更事件监听
        event(new CruiseOrderStatusChangeEvent($this->cruiseOrderModel->id, $this->cruiseOrderModel->status));

        if ($this->cruiseOrderModel->status == CruiseOrderModel::STATUS_AUDIT_ERROR){
            try {
                self::notifySelfCheckError($this->cruiseOrderModel,$this->cruiseOrderModel->cruiseCheckSelfDetailRel()->first());
            } catch (\Exception $exception){
                logException('门店自检审核推送异常',$exception);
            }
        }
    }

    public static function notifySelfCheckError(
        CruiseOrderModel $orderModel,
        CruiseCheckSelfDetailModel $detailModel
    ): bool {
        $shopId   = $orderModel->shopId;
        $shopInfo = $orderModel->shopRel()->first();
        $taskInfo = $detailModel->cruiseCheckSelfTaskRel()->first();

        $pushUsers = ShopSelfCheckNotifyConfigService::getPushUserIds($shopId);

        if (empty($pushUsers)) {
            Log::info("门店自检审核异常通知，未获取到可推送用户:$shopId");
            return false;
        }

        $title   = vsprintf("%s（%s）审核有异常", [
            $taskInfo->name,
            $detailModel->getExecuteDateText($taskInfo->rule)
        ]);
        $summary = vsprintf("%s%s的%s（%s）审核有异常，点击查看详情", [
            $shopInfo->shopCode,
            $shopInfo->name,
            $taskInfo->name,
            $detailModel->getExecuteDateText($taskInfo->rule)
        ]);
        $notify  = \App\Service\System\SystemNotifyService::save(
            false,
            $title,
            SystemNotifyCenterModel::NOTIFY_TYPE_3,
            SystemNotifyCenterModel::NOTIFY_TARGET_1,
            '',
            $title,
            config('webUrl.notify_web_cdn_url')
            . "#/pages/operate/self-check/shop-check-detail/index?id={$orderModel->id}&platform=shop",
            SystemNotifyCenterModel::METHOD_TYPE_AUTOMATIC,
            $summary,
            '',
            SystemNotifyCenterModel::IS_POPUP_ON,
            1,
            0, [], 1
        );
        \App\Service\System\SystemNotifyService::recordLog($notify, '自检审核异常');
        \App\Service\System\SystemNotifyService::preSend(
            $notify->id,
            $pushUsers
        );
        return true;
    }

    public function getManagers(): array
    {
        $shop     = ShopModel::query()->find($this->cruiseOrderModel->shopId);

        $manageId = (int)OpenShopOrganizationRegionMappingModel::query()
                                                               ->where('provinceCode', $shop->province)
                                                               ->value('manageId');

        // 督导
        $manager = OpenShopOrderManagerModel::query()
                                            ->where('shopId', $shop->id)
                                            ->where('type', OpenShopOrderManagerModel::MANAGER_TYPE_5)
                                            ->where('managerUid', '!=', 0)
                                            ->orderByDesc('id')
                                            ->first();

        if ($manager) {
            $userIds[]   = $manager->managerUid;
            $userNames[] = $manager->managerName;
        }

        // 城市经理
        OpenShopOrganizationManageUserModel::query()
                                           ->where('manageId', $manageId)
                                           ->whereIn('type', [
                                               OpenShopOrganizationManageUserModel::TYPE_CITY_MANAGER,
                                               OpenShopOrganizationManageUserModel::TYPE_DEVELOP_CITY_MANAGER
                                           ])
                                           ->select('userId', 'name', 'addressCodes', 'type')
                                           ->get()
                                           ->each(function ($item) use ($shop, &$userIds, &$userNames) {

                                               $filter = collect($item->addressCodesArr)
                                                   ->where('cityCode', $shop->city)
                                                   ->count();
                                               if (!$filter) {
                                                   return null;
                                               }

                                               $userIds[]   = $item->userId;
                                               $userNames[] = $item->name;
                                           });

        // 省总
        $provinceUser = OpenShopOrganizationManageModel::query()->where('id', $manageId)
                                                       ->select('operationUid', 'operationName')->first();
        if ($provinceUser) {
            $userIds[]   = $provinceUser->operationUid;
            $userNames[] = $provinceUser->operationName;
        }

        // 战区总
        $regionId = (int)OpenShopRegionManageMappingModel::query()
                                                         ->where('manageId', $manageId)
                                                         ->value('regionId');

        OpenShopRegionManageUserMappingModel::query()
                                            ->where('regionId', $regionId)
                                            ->where('type', OpenShopRegionManageUserMappingModel::USER_TYPE_1)
                                            ->get()
                                            ->each(function ($item) use (&$userIds, &$userNames) {
                                                $userIds[]   = $item->userId;
                                                $userNames[] = $item->username;
                                            });

        $userIds   = array_values(array_filter(array_unique($userIds)));
        $userNames = implode(',', array_values(array_filter(array_unique($userNames))));

        return [$userIds, $userNames];
    }
}
